home *** CD-ROM | disk | FTP | other *** search
- /*
- IMPACT - Virtual Reality Workshop
- First implementation by John Henckel on Oct 7, 1993
-
- Copyright (c) 1993,1995 John Henckel
- Permission to use, copy, modify, distribute and sell this software
- and its documentation for any purpose is hereby granted without fee,
- provided that the above copyright notice appear in all copies.
-
- Acknowledgements:
- * This program was developed using Borland Turbo C++ 3.0. The speed and
- versatility of the graphics of this program is a tribute to the talented
- programmers at Borland. Also their online help is fabulous.
- * The equations for collision of irregularly shaped objects are taken from
- "Dynamics" by Pestel and Thomson, 1968, I haven't found such a detailed
- analysis of this problem in any other book.
-
- Comments on ver 2.0 -- complex machines
- I wanted to have machines with movable parts and limbs. The approach
- I've taken is this. Every machine must have one root part, all other
- parts refer to this root. A sub (non-root) is connected to either the
- root or another sub by a joint. The joint determines the position
- and velocity of a sub. A part can only be connected to a body prior
- to it in the array of bodies, thus a root has a lower index than
- all its subparts. The user has interactive control over the machine
- my changing the jvx,jvy,jw -- the velocity of the joints.
-
- Note on 1/26/95 by john....
- As you may be able to tell, this code is in transition. I tried very
- hard to fit the joint mechanism into an existing simple body design.
- However, I have given up. The part about conserving rotational inertia
- while a joint is moving stumped me. Someday I would like to start over
- using c++ classes and bitmaps and real joints.
-
- Uploaded to Simtel 1/27/95.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <time.h>
- #include <math.h>
- #include <graphics.h>
- #include <dos.h>
- #include <conio.h>
- #include "mouse.h"
-
- // Macros and constants
-
- #define MA 10 // array size
- #define MB 50 // bodies
- #define MX 40 // virtual x dimension size (origin lower-left)
- #define MY 30 // virtual y size
- #define EPS 0.00001 // small number
- #define PI 3.1415926
- #define BEEP 2000 // two bodies hit
- #define BLIP 1000 // body hit wall
- #define frand(x) (x/1000.0*random(1000))
- #define rline(a,b,c,d) line((a)*xm/MX,ym-(b)*ym/MY,(c)*xm/MX,ym-(d)*ym/MY)
-
- // The following are used for timing parts of the code
- #define tini memset(timer,0,sizeof timer)
- #define tion(x) timer[x].c = clock()
- #define tiof(x) timer[x].a += clock()-timer[x].c
- #define tisw(x) tiof(x); tion(x+1)
-
- // Types
-
- typedef float fa[MA];
- typedef struct { int x,y; } pt;
-
- typedef struct { // Body: (- means scratch field)
- int color; // color of the body
- float r; // radius (maximum)
- float m; // mass
- float i; // coefficient of moment of inertia ( = I/m )
- int n; // number of points in the shape (0=ball,1=??)
- fa sx,sy; // shape (center of mass is always origin)
- fa px,py; //- corner points
- fa len; // length of each edge (from i to i+1)
- pt poly[2][MA+1]; //- polygons for draw and erase
- float vx,vy,w; // velocity
- float cx,cy,a; // center position
- float ocx,ocy,oa; //- old center position
- int rb; // root body index (must be less than my index)
- int jb; // joint body (less than mine) <or> num parts
- float jx,jy,ja; // location of pivot
- float jvx,jvy,jw; // velocity of pivot
- float kx,ky; // my offset to pivot <or> abs tot center of mass
- float tm,ti; //- total mass and moment coeff
- } body;
-
- // Global Variables
-
- int xm,ym;
- body bod[MB]; // Array of bodies
- int numb;
- int wall=15;
- struct { clock_t a,c; } timer[10];
-
- // Global options
-
- float fric=0.0; // air friction
- float grav=0.0; // gravity
- float scut=0.9; // collision center adjustment
- float rest=1.0; // coefficient of restitution
- int trace=0; // erase image on redraw
- int clear=0; // clear screen
- int mous=0; // mouse present?
- int delet=0; // delete last body
- int noisy=0; // turn on sound
- int debug=0;
- int cycle=0; // color cycling
- float covel=0.01; // maximum contact velocity
- float slid=0; // sliding friction
-
- /*----------------------------------------------------------------------
- Redraw_all - erase all bodies and redraw them in the new position
- */
- int redraw_all(int p)
- {
- int b;
-
- if (clear) {
- cleardevice();
- wall=15;
- clear=0;
- }
- for (b=0; b<numb; ++b) {
- setcolor(0); // black
- if (!trace) drawpoly(bod[b].n+1,(int*)bod[b].poly[1-p]);
- if (b<numb-delet) {
- if (cycle) bod[b].color = (bod[b].color+1)&255;
- setcolor(bod[b].color);
- drawpoly(bod[b].n+1,(int*)bod[b].poly[p]);
- }
- }
- numb -= delet;
- if (numb<0) numb=0;
- delet=0;
-
- setcolor(1);
- if (wall&1) line(0,0,xm,0);
- if (wall&2) line(xm,0,xm,ym);
- if (wall&4) line(xm,ym,0,ym);
- if (wall&8) line(0,ym,0,0);
- wall=0;
-
- return 0;
- }
-
- /*----------------------------------------------------------------------
- draw mouse pointer
- */
- int draw_mouse(int x, int y, int c)
- {
- setcolor(c);
- line(x+5,y+5,x-5,y-5);
- line(x-5,y+5,x+5,y-5);
- return 0;
- }
-
- /*-----------------------------------------------------------------
- add new bodies - see help message in get_input
- */
- void addnew(char *s)
- {
- int i,j,k,c,n,x;
- float d,t,x1,y1,a,m;
-
- n=1; j=4; d=1; x1=1; c=0; y1=0.0001; m=0; a=0; // defaults
- memset(&bod[numb],0,sizeof *bod);
- bod[numb].cx = bod[numb].cy = 0.5;
- bod[numb].rb = numb;
- sscanf(s,"%d %d %f %f %d %f %f %f %f %f %f %f %f %f"
- " %d %d %f %f %f %f %f %f %f %f",
- &n,&j,&x1,&d,&c,&y1,&m,&a,
- &bod[numb].cx,&bod[numb].cy,&bod[numb].a,
- &bod[numb].vx,&bod[numb].vy,&bod[numb].w,
- &bod[numb].rb,&bod[numb].jb,
- &bod[numb].jx,&bod[numb].jy,&bod[numb].ja,
- &bod[numb].jvx,&bod[numb].jvy,&bod[numb].jw,
- &bod[numb].kx,&bod[numb].ky);
- if (d<EPS) d=0.1;
- if (d>2) d=2;
- if (m==0) m=PI*d*d*x1*100;
- if (a==0) a=d*d*x1;
- if (j<2) j=2;
- if (j>=MA) j=MA-1;
- if (n<0) n=0;
- if (n+numb > MB) n=MB-numb;
- if (y1>1) y1=1;
-
- // Set up the first new body
- bod[numb].color = c;
- bod[numb].r = d*x1;
- bod[numb].m = m;
- bod[numb].i = a;
-
- for (i=numb; i<numb+n; ++i) {
- bod[i] = bod[numb];
- bod[i].rb = i-numb+bod[numb].rb; // ??
- if (c==0) bod[i].color=9+i%6;
- if (i>numb) {
- bod[i].cy = bod[i-1].cy + 2*d;
- bod[i].cx = bod[i-1].cx;
- }
- if (bod[i].cy+d > MY) {
- bod[i].cy = 0.5;
- bod[i].cx = bod[i-1].cx + 2*d*x1;
- }
- bod[i].n = j;
- for (k=0; k<j; ++k) {
- bod[i].sx[k] = d*(1-frand(y1))*cos(PI*2*(k+0.5+frand(y1))/j)*-x1;
- bod[i].sy[k] = d*(1-frand(y1))*sin(PI*2*(k+0.5+frand(y1))/j);
- }
- for (k=0; k<bod[i].n; ++k) {
- x = k+1; if (x==bod[i].n) x=0;
- bod[i].len[k] = hypot(bod[i].sx[k]-bod[i].sx[x],
- bod[i].sy[k]-bod[i].sy[x]);
- if (bod[i].len[k] < EPS) bod[i].len[k] = EPS;
- }
- bod[i].w += frand(PI*y1);
- }
- numb += n;
- }
-
- /*----------------------------------------------------------------------
- help - display help
- */
- int help(void)
- {
- gotoxy(1,1);
- printf("IMPACT Dynamics Simulator. Version 2.1 ("__DATE__")\n");
- printf(" by John Henckel, henckel@vnet.ibm.com\n\n");
- printf("Press a to add a new bodies\n");
- printf("Press c to clear screen\n");
- printf("Press d to delete the last body\n");
- printf("Press e for an energy report\n");
- printf("Press f to change air friction [0.0] ");
- printf("[] = default\n");
- printf("Press g to change gravitation constant [0.0]\n");
- printf("Press j to change body center adjustment factor [.9]\n");
- printf("Press q to toggle sound\n");
- printf("Press r to change restitution coefficient [1.0]\n");
- printf("Press s to change sliding friction [0]\n");
- printf("Press t to toggle trace mode [0]\n");
- printf("Press v to change sliding threshold vel [.01]\n");
- printf("Press x to toggle debug mode [0]\n");
- printf("Press y to cycle colors\n");
- printf("Press ? or F1 for help\n");
- if (mous) {
- printf("You can use the mouse to pull things.\n");
- printf(" button 1=pull, button 2=stop spin, both=pull ALL!\n");
- }
- printf("\nPress a key to continue\n");
- while (!kbhit());
- return clear=1;
- }
-
- /*----------------------------------------------------------------------
- msg - display a message on the message line
- */
- int msg(int c,char *s)
- {
- gotoxy(5,c+2);
- printf("%s",s);
- return clear=1;
- }
- int msgd(int c,char *s,int d)
- {
- char x[80];
- sprintf(x,"%-30s %d",s,d);
- return msg(c,x);
- }
- int msgf(int c,char *s,float d)
- {
- char x[80];
- sprintf(x,"%-30s %9.7f",s,d);
- return msg(c,x);
- }
-
-
- /*----------------------------------------------------------------------
- get_input and redraw mouse pointer
- */
- #define VV 0.1
- int get_input(void)
- {
- static int b=-1,x=0,y=0;
- static char s[320];
- int i,j,k,c,n;
- float d,t,x1,y1,a,m;
-
- nosound();
- if (!numb) {
- help();
- cleardevice();
- }
- if (mous) {
- draw_mouse(x,y,0);
- b=get_mouse(&x,&y);
- draw_mouse(x,y,15-b);
- } else b=0;
- if (b) {
- x1 = 1.0*x/xm*MX;
- y1 = (1-1.0*y/ym)*MY;
- if (b<3) {
- d = 99999; // find closest body
- for (j=i=0; i<numb; ++i) {
- t = hypot(x1-bod[i].cx,y1-bod[i].cy);
- if (t < d) { d=t; j=i; }
- }
- if (d > EPS) {
- bod[j].vx = (x1-bod[j].cx)*VV;
- bod[j].vy = (y1-bod[j].cy)*VV;
- }
- if (b>1) bod[j].w = 0; // stop spin
- }
- else { // attract everything
- for (j=0; j<numb; ++j) {
- bod[j].vx = (x1-bod[j].cx)*VV*0.1;
- bod[j].vy = (y1-bod[j].cy)*VV*0.1;
- }
- }
- }
- if (kbhit()) {
- while (kbhit()) b=getch(); // skip over typeahead and extended codes
- if (b==27) return 1;
- if (b=='g') {
- msg(0,"Enter gravitation constant*10000 (-10.0 to 10.0): ");
- scanf("%f",&grav);
- grav /= 10000;
- }
- if (b=='f') {
- msg(0,"Enter air friction constant (0.0-100.0): ");
- scanf("%f",&fric);
- }
- if (b=='r') {
- msg(0,"Enter coefficient of restitution (0.0 - 1.0): ");
- scanf("%f",&rest);
- if (rest<-1) rest=-1;
- if (rest>2) rest=2;
- }
- if (b=='v') {
- msg(0,"Enter sliding impact threshold (0.0 - 0.1): ");
- scanf("%f",&covel);
- }
- if (b=='s') {
- msg(0,"Enter sliding friction (0.0 - 1.0): ");
- scanf("%f",&slid);
- if (slid< -0.9) slid=-0.9;
- }
- if (b=='e') {
- t=a=d=m=0;
- for (i=0; i<numb; ++i) {
- t += 0.5*bod[i].m*(bod[i].vx*bod[i].vx + bod[i].vy*bod[i].vy);
- a += 0.5*bod[i].m*bod[i].i*bod[i].w*bod[i].w;
- d += bod[i].m*bod[i].cy*grav;
- }
- m=t+a+d;
- msgd(0,"Total number of bodies",numb);
- msgf(1,"Total translation energy",t);
- msgf(2,"Total rotation energy",a);
- msgf(3,"Total potential energy",d);
- msgf(4,"Total energy",m);
- msgf(6,"Gravitation",grav);
- msgf(7,"Friction",fric);
- msgf(8,"Restitution coefficient",rest);
- msgf(9,"Collision adjustment",scut);
- msgf(10,"Sliding threshold vel",covel);
- msgf(11,"Sliding friction",slid);
- msgd(12,"Mouse detected",mous);
- msgd(13,"Debug mode",debug);
- while (!kbhit());
- }
- if (b=='j') {
- msg(0,"Enter collision center adjustment (0.0 - 1.0): ");
- scanf("%f",&scut);
- if (scut<-1) scut=-1;
- if (scut>2) scut=2;
- }
- if (b=='q') noisy^=1;
- if (b=='y') cycle^=1;
- if (b=='d') delet=1;
- if (b=='a' && numb<MB) { // Add new body
- msg(0,"Enter data: Count[1] Sides[4] Aspect[1] Radius[1] Color[0?]");
- msg(1," Noise[0] Mass[0] Moment[0] Pos[.5 .5 0] Vel[0 0 0]");
- msg(2,"[] = default. Default mass and moment is based on radius, "
- "unit density.");
- msg(3,"For example, for five rectangles type: 5 4 2\n");
- do { gets(s); } while(*s < ' ');
- addnew(s);
- }
- if (b=='t') trace^= 1;
- if (b=='c') clear = 1;
- if (b=='x') debug = 1;
- if (b=='?' || b==';') help();
- }
- return 0;
- }
-
- /*----------------------------------------------------------------------
- computes new c,a += new v,w
- */
- int compute_new(void)
- {
- int b;
- float sa,ca;
- float sx,sy;
- for (b=0; b<numb; ++b)
- if (bod[b].rb < b) { // a sub part
- bod[b].jx += bod[b].jvx;
- bod[b].jy += bod[b].jvy;
- bod[b].ja += bod[b].jw;
- }
- else { // a root part
- bod[b].cx += bod[b].vx + (bod[b].ky - bod[b].cy)*bod[b].w;
- bod[b].cy += bod[b].vy + (bod[b].cx - bod[b].kx)*bod[b].w;
- bod[b].a += bod[b].w;
- }
- return 0;
- }
-
- /*----------------------------------------------------------------------
- sets px,py (corners) based on shape and cx,cy (center), a (angle)
- */
- int compute_pxy(void)
- {
- int i,b;
- float cx,cy,ca,sa;
-
- for (b=0; b<numb; ++b) {
- cx = bod[b].cx;
- cy = bod[b].cy;
- ca = cos(bod[b].a);
- sa = sin(bod[b].a);
-
- for (i=0; i<bod[b].n; ++i) {
- bod[b].px[i] = cx + bod[b].sx[i]*ca - bod[b].sy[i]*sa;
- bod[b].py[i] = cy + bod[b].sx[i]*sa + bod[b].sy[i]*ca;
- }
- }
- return 0;
- }
-
- /*----------------------------------------------------------------------
- set_old - copy new c,a,v,w to old.
- */
- int set_old(void)
- {
- int b;
- for (b=0; b<numb; ++b) {
- bod[b].ocx = bod[b].cx;
- bod[b].ocy = bod[b].cy;
- bod[b].oa = bod[b].a ;
- }
- return 0;
- }
-
- /*----------------------------------------------------------------------
- copy px,py to poly[p], adjust for scale.
- the range of pxy is [MX,MY], poly is [xm,ym] y inverted.
- */
- int set_poly(int p)
- {
- int i,b;
-
- for (b=0; b<numb; ++b) {
- for (i=0; i<bod[b].n; ++i) {
- bod[b].poly[p][i].x = bod[b].px[i]*xm/MX;
- bod[b].poly[p][i].y = (MY-bod[b].py[i])*ym/MY;
- }
- bod[b].poly[p][i].x = bod[b].poly[p][0].x; // close the polygon
- bod[b].poly[p][i].y = bod[b].poly[p][0].y;
- }
- return 0;
- }
-
- /*----------------------------------------------------------------------
- distance from a point to a line (the edge of another body).
- result is negative inside (clockwise).
- */
- float dptl(float x,float y,int b,int i)
- {
- int t;
- float nx,ny;
- t = i+1;
- if (t==bod[b].n) t=0;
- nx = bod[b].py[i] - bod[b].py[t];
- ny = bod[b].px[t] - bod[b].px[i]; // n is normal vector
- x -= bod[b].px[i];
- y -= bod[b].py[i];
- nx = (x*nx + y*ny) / bod[b].len[i];
- return nx;
- }
-
- /*-----------------------------------------------------------------
- adjust machines - this routine adjusts
- 1. the roots of every machine by setting: center of mass, total mass
- and inertia, num bodies
- 2. the subparts of every machine by setting: position, velocity
- */
- int adjust_parts() {
- int b,r,j;
- float ca,sa,px,py,rx,ry;
-
- for (b=0; b<numb; ++b) {
- r = bod[b].rb;
- if (r>=b) {
- bod[b].jb = 0; // num sub parts
- bod[b].kx = bod[b].cx;
- bod[b].ky = bod[b].cy;
- bod[b].tm = bod[b].m;
- bod[b].ti = bod[b].i*bod[b].m;
- }
- else {
- j=bod[b].jb;
- if (j<r || j>=b) bod[b].jb=j=r; // require r <= j < b
- /*-----------------------------------------------------------------
- figure out the position of b
- */
- ca = cos(bod[j].a);
- sa = sin(bod[j].a);
- px = bod[j].cx + ca*bod[b].jx - sa*bod[b].jy;
- py = bod[j].cy + ca*bod[b].jy + sa*bod[b].jx;
- // setcolor(15); rline(bod[j].cx,bod[j].cy,px,py);
- bod[b].a = bod[j].a + bod[b].ja;
- ca = cos(bod[b].a);
- sa = sin(bod[b].a);
- rx = ca*bod[b].kx - sa*bod[b].ky;
- ry = ca*bod[b].ky + sa*bod[b].kx;
- if (debug)
- ca=1;
- bod[b].cx = px - rx;
- bod[b].cy = py - ry;
- // setcolor(15); rline(bod[b].cx,bod[b].cy,px,py); for debugging joints
- /*-----------------------------------------------------------------
- figure out the velocity of b
- */
- px = bod[b].cx - bod[j].cx;
- py = bod[b].cy - bod[j].cy;
- bod[b].vx = bod[j].vx + bod[b].jvx - py*bod[j].w + ry*bod[b].jw;
- bod[b].vy = bod[j].vy + bod[b].jvy + px*bod[j].w + rx*bod[b].jw;
- bod[b].w = bod[j].w + bod[b].jw;
- /*-----------------------------------------------------------------
- update root totals
- */
- ++bod[r].jb;
- px = bod[r].tm + bod[b].m;
- bod[r].kx = (bod[r].kx*bod[r].tm + bod[b].cx*bod[b].m) / px;
- bod[r].ky = (bod[r].ky*bod[r].tm + bod[b].cy*bod[b].m) / px;
- bod[r].tm = px;
- px = bod[r].cx - bod[j].cx;
- py = bod[r].cy - bod[j].cy;
- bod[r].ti += bod[b].m*(px*px + py*py); // I = mr^2
- }
- }
- return 0;
- }
- /*-----------------------------------------------------------------
- collision - test for a collision between two bodies, if so,
- return the point of impact, and unit vector normal to surface
- of impact (points into b2), and penetration distance.
- */
- int collision(int b1,int b2,
- int *B1,int *B2,
- float *hx,float *hy,
- float *nx,float *ny,float *pen)
- {
- float d1,d2,dd,d,px,py;
- int i,j,i1,i2,k1,k2,t=0;
- /*-----------------------------------------------------------------
- If both bodies are part of the same machine, ignore collision
- */
- if (bod[b1].rb==bod[b2].rb) return 0;
- /*-----------------------------------------------------------------
- The following is for efficiency. If the centers are far apart,
- then don't test for collision.
- */
- d1 = fabs(bod[b1].cx - bod[b2].cx);
- d2 = fabs(bod[b1].cy - bod[b2].cy);
- d = bod[b1].r + bod[b2].r;
- if (d1 > d || d2 > d) return 0;
- /*-----------------------------------------------------------------
- First test for corners of b1 inside b2, then b2 inside b1
- */
- dd = 0;
- while (++t < 3) {
- for (i=0; i<bod[b1].n; ++i) {
- px = bod[b1].px[i];
- py = bod[b1].py[i];
- d1 = d2 = -99999;
- for (j=0; j<bod[b2].n; ++j) {
- d = dptl(px,py,b2,j);
- if (d > EPS) break; // not inside
- if (d > d1) {
- d2=d1; i2=i1; // d2 is second best
- d1=d; i1=j; // d1 is dist to nearest edge
- }
- else if (d > d2) {
- d2=d; i2=j; // d2 is second best
- }
- }
- /*-----------------------------------------------------------------
- The following bit of code is usually not necessary, usually
- we can bounce corner i off of edge i1. However, sometimes the
- correct edge is the second best, i2. This is when the corners
- adjacent to i, k1 and k2, are not farther from edge i1 than i.
- */
- k1 = i-1; if (k1<0) k1 = bod[b1].n-1;
- k2 = i+1; if (k2==bod[b1].n) k2 = 0;
- if (j==bod[b2].n && j>2 &&
- (d1 > dptl(bod[b1].px[k1],bod[b1].py[k1],b2,i1) ||
- d1 > dptl(bod[b1].px[k2],bod[b1].py[k2],b2,i1)) &&
- d2 < dptl(bod[b1].px[k1],bod[b1].py[k1],b2,i2) &&
- d2 < dptl(bod[b1].px[k2],bod[b1].py[k2],b2,i2)) {
- i1 = i2;
- d1 = d2;
- }
- /*-----------------------------------------------------------------
- Store parameters for this bounce
- */
- if (j==bod[b2].n && d1<dd) { // maximum penetration
- dd = d1;
- i2 = i1+1; // i2 = other end point of the edge
- if (i2==bod[b2].n) i2=0;
- *ny = (bod[b2].px[i1] - bod[b2].px[i2])/bod[b2].len[i1];
- *nx = (bod[b2].py[i2] - bod[b2].py[i1])/bod[b2].len[i1];
- *hx = px; // + *nx*d1;
- *hy = py; // + *ny*d1;
- *B1 = b1;
- *B2 = b2;
- *pen = -d1;
- }
- }
- i = b1; b1 = b2; b2 = i; // swap b1 and b2
- }
- if (dd == 0) return 0; // no collision found between these bodies
- if (debug) {
- setcolor(15);
- rline(*hx,*hy,*hx+*nx/10,*hy+*ny/10);
- while (!kbhit()); // wait for keypress
- i=getch();
- if (i=='x') debug=0;
- }
- if (noisy) sound(BEEP);
- return 1;
- }
-
- /*----------------------------------------------------------------------
- get_accel - get any changes to velocity from collisions, gravity, etc
- */
- int get_accel(void)
- {
- int t,t1,t2;
- int i1,b1,b2,r;
- static float x1,x2,y1,y2,v1,v2,c1,c2,w1,w2,m1,m2,o1,o2;
- static float nx,ny,z,a1,a2,a,b,c,hx,hy,ri;
-
- // test if any body bumped into a wall
-
- for (b1=0; b1<numb; ++b1) {
- x1=MX; x2=0;
- for (i1=0; i1<bod[b1].n; ++i1) {
- if (x1 > bod[b1].px[i1]) { // find leftmost
- x1=bod[b1].px[i1];
- y1=bod[b1].py[i1];
- }
- if (x2 < bod[b1].px[i1]) { // find rightmost
- x2=bod[b1].px[i1];
- y2=bod[b1].py[i1];
- }
- }
- if (x2 > MX) { x1=x2-MX; y1=y2; wall|=2; }
- else if (x1 > 0) x1=0;
- else wall|=8;
- if (x1) {
- if (debug) {
- setcolor(15);
- a = x1<0 ? 0 : MX-.1;
- rline(a,y1,a+.1,y1);
- while (!kbhit()); // wait for keypress
- if (getch()=='x') debug=0;
- }
- if (noisy) sound(BLIP);
- r = bod[b1].rb; // root of machine
- ri = bod[r].ti/bod[r].tm;
- y1 = bod[r].ky - y1;
- w1 = bod[b1].w; // ??? b1 or r ???
- v1 = bod[b1].vx;
- a = y1*y1/ri;
- c1 = ((a-rest)*v1 - y1*(1+rest)*w1)/(a+1);
- bod[r].vx = c1;
- bod[r].w = y1*(c1 - v1)/ri + w1; // - jw ??
- bod[r].cx -= scut*x1;
- }
- y1=MY; y2=0;
- for (i1=0; i1<bod[b1].n; ++i1) {
- if (y1 > bod[b1].py[i1]) { // find bottommost
- x1=bod[b1].px[i1];
- y1=bod[b1].py[i1];
- }
- if (y2 < bod[b1].py[i1]) { // find topmost
- x2=bod[b1].px[i1];
- y2=bod[b1].py[i1];
- }
- }
- if (y2 > MY) { y1=y2-MY; x1=x2; wall|=1; }
- else if (y1 > 0) y1=0;
- else wall|=4;
- y2=y1;
- if (y2) {
- if (debug) {
- setcolor(15);
- a = y2<0 ? 0 : MY-.1;
- rline(x1,a,x1,a+.1);
- while (!kbhit()); // wait for keypress
- if (getch()=='x') debug=0;
- }
- if (noisy) sound(BLIP);
- r = bod[b1].rb; // root of machine
- ri = bod[r].ti/bod[r].tm;
- y1 = -bod[r].kx + x1;
- w1 = bod[b1].w;
- v1 = bod[b1].vy;
- a = y1*y1/ri;
- c1 = ((a-rest)*v1 - y1*(1+rest)*w1)/(a+1);
- bod[r].vy = c1;
- bod[r].w = y1*(c1 - v1)/ri + w1; // - jw ??
- bod[r].cy -= scut*y2;
- /*----------------------------------------------------------
- Do sliding friction on the floor (or ceiling)
- */
- z = bod[b1].vx; // relative sliding velocity
- z *= 1-1/(slid+1);
- bod[b1].vx -= z;
- }
- }
- // For every pair of shapes, test if any of b1's corners are inside b2.
-
- for (t1=0; t1<numb; ++t1)
- for (t2=t1+1; t2<numb; ++t2)
- if (collision(t1,t2,&b1,&b2,&hx,&hy,&nx,&ny,&z)) {
- // Prepare to compute collision
- r = bod[b1].rb; // root of machine
- ri = bod[r].ti/bod[r].tm;
- r = bod[b1].rb; // root of machine
- ri = bod[r].ti/bod[r].tm;
- v1 = bod[b1].vx*nx + bod[b1].vy*ny;
- v2 = bod[b2].vx*nx + bod[b2].vy*ny;
- y1 = (hx-bod[b1].ocx)*ny - (hy-bod[b1].ocy)*nx;
- y2 = (hx-bod[b2].ocx)*ny - (hy-bod[b2].ocy)*nx;
- w1 = bod[b1].w;
- w2 = bod[b2].w;
- m1 = bod[b1].m;
- m2 = bod[b2].m;
- a1 = bod[b1].i;
- a2 = bod[b2].i;
- /*--------------------------------------------------------------------
- find change in velocity using "Dynamics" impact equations
- */
- a = (a1*m1*y2*y2 + a2*m2*y1*y1)/(a1*a2);
- b = m1 + m2;
- if (b < EPS) break; // mass is too small
- c = y1*w1 - y2*w2;
- c1 = ((a + m1 - rest*m2)*v1 + (1+rest)*m2*(v2 - c)) / (a + b);
- c2 = ((a + m2 - rest*m1)*v2 + (1+rest)*m1*(v1 + c)) / (a + b);
- o1 = y1*(c1 - v1)/a1;
- o2 = y2*(c2 - v2)/a2;
- bod[b1].w += o1;
- bod[b2].w += o2;
- bod[b1].vx += nx*(c1 - v1);
- bod[b1].vy += ny*(c1 - v1);
- bod[b2].vx += nx*(c2 - v2);
- bod[b2].vy += ny*(c2 - v2);
- /*--------------------------------------------------------------------
- adjust the centers of the two bodies so they aren't overlapped,
- movement is inversely proportional to mass.
- */
- z *= scut/b;
- bod[b1].cx -= nx*z*m2;
- bod[b1].cy -= ny*z*m2;
- bod[b2].cx += nx*z*m1;
- bod[b2].cy += ny*z*m1;
- /*-----------------------------------------------------------------
- Compute sliding friction
- */
- a = v1 - v2; // approach velocity
- if (fabs(a) < covel) {
- c1 = bod[b1].vy*nx - bod[b1].vx*ny;
- c2 = bod[b2].vy*nx - bod[b2].vx*ny;
- z = c1 - c2; // relative sliding velocity
- z *= 1-1/(slid+1);
- z /= b;
- bod[b1].vx += ny*z*m2;
- bod[b1].vy -= nx*z*m2;
- bod[b2].vx -= ny*z*m1;
- bod[b2].vy += nx*z*m1;
- }
- }
-
- // Add air friction and gravity
- // and check for centers out of range
-
- for (b1=0; b1<numb; ++b1) {
- z = hypot(bod[b1].vx,bod[b1].vy);
- z = 1/(1+z*fric); // air friction
- bod[b1].vy *= z;
- bod[b1].vx *= z;
- bod[b1].vy -= grav; // gravity
-
- t = 0;
- if (bod[b1].cx < 0) { t=1; bod[b1].cx = 0; }
- if (bod[b1].cx >MX) { t=1; bod[b1].cx = MX; }
- if (bod[b1].cy < 0) { t=1; bod[b1].cy = 0; }
- if (bod[b1].cy >MY) { t=1; bod[b1].cy = MY; }
- if (t) {
- bod[b1].vx *= 0.9; // slow it down!
- bod[b1].vy *= 0.9;
- bod[b1].w *= 0.9;
- }
- }
- return 0;
- }
- /*----------------------------------------------------------------------
- Animate
- This is the main action loop of the program.
- On entry these must be set.
- bod, numb, xm, ym
- and graphics screen must be up and clear.
- */
- int animate(void)
- {
- int p=0;
-
- adjust_parts(); // set subpart new c,a
- compute_pxy(); // compute corners based on new c,a
- set_poly(p); // initialize old poly
-
- while (1) {
- p = 1-p; tion(0);
- if (get_input()) break; tisw(0); // test mouse and keyboard
- set_old(); tisw(1); // set old c,a to new ones.
- compute_new(); tisw(2); // new c,a = old c,a + v,w
- adjust_parts(); // set subpart new c,a
- compute_pxy(); tisw(3); // compute corners based on new c,a
- set_poly(p); tisw(4); // set poly based on corners
- redraw_all(p); tisw(5); // erase and draw all bodies
- set_old(); tisw(6); // set old c,a to new ones. ???
- get_accel(); tiof(7); // test for any collisions, etc
- }
- return 0;
- }
-
- /*-----------------------------------------------------------------
- readfile
- */
- void readfile(char *filename)
- {
- char s[256];
- FILE *f;
- f = fopen(filename,"r");
- if (f==NULL) return;
- fgets(s,sizeof s,f);
- sscanf(s,"%f %f %f %f %d %f %f",&fric,&grav,&scut,&rest,&trace,&covel,&slid);
- while (1) {
- if (!fgets(s,sizeof s,f)) break;
- if (*s>30) addnew(s);
- }
- fclose(f);
- }
-
- /*----------------------------------------------------------------------
- M A I N
- */
- int main(int argc, char **argv)
- {
- int i,gm,gd=0;
-
- printf("IMPACT Dynamics Simulator. Version 2.1 ("__DATE__")\n");
- printf(" by John Henckel, henckel@vnet.ibm.com\n\n");
- printf("Copyright (c) 1993,1995 John Henckel\n");
- printf("Permission to use, copy, modify, distribute and sell this software\n");
- printf("and its documentation for any purpose is hereby granted without fee,\n");
- printf("provided that the above copyright notice appear in all copies.\n");
- if (argc<2) {
- printf("\nParms: filename -mono\n\n");
- printf("If you have EGA/VGA, then do not specify -mono.\n");
- printf("If you have CGA, Hercules, or other .bgi type, specify -mono.\n");
- i=10; while (!kbhit() && --i) delay(500);
- }
- if (argc<3)
- registerbgidriver(EGAVGA_driver); // omit this line to use .BGI file
- initgraph(&gd,&gm,"");
- srand(time(NULL));
- if (graphresult() != grOk) return
- printf("\nUnable to initialize graphics adapter\n");
- xm = getmaxx();
- ym = getmaxy();
- if (init_mouse()==-1) {
- mous = 1;
- hide_mouse(); // we make our own pointer.
- }
- numb = 0;
- if (argc>1) readfile(argv[1]);
- tini;
- animate();
- closegraph();
- for (gm=0; gm<10; ++gm)
- if (timer[gm].a) printf("timer %d is %10d\n",gm,timer[gm].a);
- return 0;
- }
-